package org.hackystat.devcathlon.engine.profile;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hackystat.devcathlon.engine.user.User;
import org.hibernate.HibernateException;
import org.hackystat.devcathlon.engine.db.hibernate.HibernateUtil;

/**
 * A thread-safe singleton class that manages access to user-profiles.
 * 
 * @author anthony.m.du
 */
public class ProfileManager {

  /** The singleton instance. */
  private static ProfileManager theInstance = new ProfileManager();

  /** The private constructor. */
  private ProfileManager() {
    // does nothing at this point; will initialize from database later.
  }

  /**
   * Returns the singleton instance of the ProfileManager.
   * 
   * @return The ProfileManager.
   */
  public static ProfileManager getInstance() {
    return ProfileManager.theInstance;
  }

  /**
   * Creates or updates a profile.
   * @param user The profile user.
   * @param gender The profile gender.
   * @param location The profile location.
   * @param contact The profile contact.
   * @param bioInfo The profile bio.
   * @param avatar The profile avatar.
   * @return The profile of interest
   */
  public synchronized Profile addProfile(User user, String gender,
      String location, String contact, String bioInfo, String avatar) {

    String email = user.getEmail();
    String firstName = user.getFirstName();
    String lastName = user.getLastName();

    Profile profile = getProfile(email);
    if (null != profile) {
      return profile;
    }
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      // Also create a profile. Profile and User classes are synonymous.
      profile = new Profile();
      profile.setScreenName(email);
      profile.setFirstName(firstName);
      profile.setLastName(lastName);
      profile.setGender(gender);
      profile.setContact(contact);
      profile.setLocation(location);
      profile.setBioInfo(bioInfo);
      profile.setAvatar(avatar);
      profile.addEmail(email);
      profile.setUser(user);
      user.setProfile(profile);
      session.update(user);
      session.saveOrUpdate(profile);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return profile;
  }

  /**
   * Returns the selected profile from the system.
   * 
   * @param email
   *          The profile's email.
   * @return The profile
   */
  public synchronized Profile getProfile(String email) {
    Profile profile = null;
    String hqlSelect = "from User u where u.email = :email";
    
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      Query query = session.createQuery(hqlSelect).setString("email", email);
      User user = (User) query.uniqueResult();
      if (null == user) {
        return profile;
      }
      profile = user.getProfile();  
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return profile;
  }
  
  /**
   * Update a specified profile.
   * 
   * @param profile The profile.
   * @return The updated profile.
   */
  public synchronized Profile updateProfile(Profile profile) {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      session.update(profile);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return profile;
  }
  
  /**
   * Deletes a profile from the system.
   * 
   * @param email The user's email.
   */
  public synchronized void deleteProfile(String email) {
    Profile profile = getProfile(email);
    if (null == profile) {
      return;
    }
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      session.delete(profile);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
  }
  
  /**
   * Returns a list of all profiles in the system.
   * 
   * @return The list of profiles
   */
  public synchronized List<?> getProfiles() {
    List<?> profiles = null;
    String hqlSelect = "from Profile";
    
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      Query query = session.createQuery(hqlSelect);
      profiles = query.list();
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return profiles; 
  }
}
